﻿using Cinch;
using FR.SAFTAnalyser.Model;
using FR.SAFTAnalyser.ViewModels.Pane;
using MEFedMVVM.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FR.SAFTAnalyser.ViewModels
{
    public class PaymentsViewModel : DocumentPartViewModel
    {
        public PaymentsViewModel()
            : base("Recibos")
        {
            if (!Designer.IsInDesignMode)
            {
                Mediator.Instance.Register(this);

                DoOpenExcelCommand = new SimpleCommand<object, object>(CanOpenExcel, OpenExcel);
                ShowInvoiceDetailsCommand = new SimpleCommand<object, object>(CanShowInvoiceDetails, DoShowInvoiceDetails);
                ShowCustomerCommand = new SimpleCommand<object, object>(CanShowCustomer, DoShowCustomer);
                
                this.filtroDataInicio = DateTime.MinValue;
                this.FiltroDataFim = DateTime.MaxValue;
            }
        }

        internal override void ResetSaftFile()
        {
            this.Payments = null;
            this.Payment = null;
            this.CurrentPayment = null;
            this.CurrentPaymentLines = null;
            this.CurrentPaymentLine = null;
        }

        #region Mediator messages
        [MediatorMessageSink(MessageType.SAFT_FILE_OPENED)]
        private void LoadInvoices(AuditFile saft)
        {
            if (saft != null && saft.SourceDocuments != null)
                this.Payments = saft.SourceDocuments.Payments;
        }
        #endregion

        #region Binding properties
        SourceDocumentsPayments payments;
        public SourceDocumentsPayments Payments
        {
            get
            {
                if (payments == null && SAFT.SaftAnalyser.Instance.SaftFile != null)
                    payments = SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.Payments;

                return payments;
            }
            set
            {
                payments = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.Payments));

                if (payments != null && string.IsNullOrEmpty(this.FilterPayment))
                {
                    DocNumberOfEntries = payments.Payment.Length;
                    DocTotalCredit = payments.Payment
                                             .Where(c => c.DocumentStatus.PaymentStatus != PaymentStatus.A)
                                             .Sum(c => c.Line.Sum(l => l.ItemElementName == ItemChoiceType9.CreditAmount ? l.Item : 0))
                                             .ToString("c");

                    DocTotalDebit = payments.Payment
                                            .Where(c => c.DocumentStatus.PaymentStatus != PaymentStatus.A)
                                            .Sum(c => c.Line.Sum(l => l.ItemElementName == ItemChoiceType9.DebitAmount ? l.Item : 0))
                                            .ToString("c");

                    NumberOfEntries = payments.NumberOfEntries;
                    TotalCredit = payments.TotalCredit.ToString("c");
                    TotalDebit = payments.TotalDebit.ToString("c");

                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.DocNumberOfEntries));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.DocTotalCredit));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.DocTotalDebit));

                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.NumberOfEntries));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.TotalCredit));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.TotalDebit));

                    this.filtroDataInicio = payments.Payment.Min(i => i.DocumentStatus.PaymentStatusDate);
                    this.filtroDataFim = payments.Payment.Max(i => i.DocumentStatus.PaymentStatusDate);

                    this.Payment = payments.Payment;
                }
            }
        }

        SourceDocumentsPaymentsPayment[] payment;
        public SourceDocumentsPaymentsPayment[] Payment
        {
            get { return payment; }
            set
            {
                payment = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.Payment));
            }
        }

        SourceDocumentsPaymentsPayment currentPayment;
        public SourceDocumentsPaymentsPayment CurrentPayment
        {
            get { return currentPayment; }
            set
            {
                currentPayment = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.CurrentPayment));

                if (currentPayment != null && string.IsNullOrEmpty(this.FilterLines))
                {
                    DocGrossTotal = currentPayment.Line.Sum(c => c.Item * (1 + c.Tax.Item * 0.01m) * Operation(c)).ToString("c");
                    DocNetTotal = currentPayment.Line.Sum(c => c.Item * Operation(c)).ToString("c");
                    DocTaxPayable = currentPayment.Line.Sum(c => c.Item * c.Tax.Item * 0.01m * Operation(c)).ToString("c");

                    GrossTotal = currentPayment.DocumentTotals.GrossTotal.ToString("c");
                    NetTotal = currentPayment.DocumentTotals.NetTotal.ToString("c");
                    TaxPayable = currentPayment.DocumentTotals.TaxPayable.ToString("c");

                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.DocGrossTotal));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.DocNetTotal));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.DocTaxPayable));

                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.GrossTotal));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.NetTotal));
                    NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.TaxPayable));

                    if (!this.ShowAllLines)
                        this.CurrentPaymentLines = currentPayment.Line;
                }
            }
        }

        SourceDocumentsPaymentsPaymentLine[] currentPaymentLines;
        public SourceDocumentsPaymentsPaymentLine[] CurrentPaymentLines
        {
            get { return currentPaymentLines; }
            set
            {
                currentPaymentLines = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.CurrentPaymentLines));
            }
        }

        SourceDocumentsPaymentsPaymentLine currentPaymentLine;
        public SourceDocumentsPaymentsPaymentLine CurrentPaymentLine
        {
            get { return currentPaymentLine; }
            set
            {
                currentPaymentLine = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.CurrentPaymentLine));
            }
        }

        bool showAllLines;
        public bool ShowAllLines
        {
            get { return showAllLines; }
            set
            {
                showAllLines = value;
                NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.ShowAllLines));

                if (showAllLines)
                    this.CurrentPaymentLines = Payments.Payment.SelectMany(i => i.Line).ToArray();
                else
                    this.CurrentPaymentLines = CurrentPayment.Line;
            }
        }

        DateTime filtroDataInicio;
        public DateTime FiltroDataInicio
        {
            get { return filtroDataInicio; }
            set
            {
                filtroDataInicio = value;
                FilterInvoicesByDate();
                NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.FiltroDataInicio));
            }
        }
        DateTime filtroDataFim;
        public DateTime FiltroDataFim
        {
            get { return filtroDataFim; }
            set
            {
                filtroDataFim = value;
                FilterInvoicesByDate();
                NotifyPropertyChanged(ObservableHelper.CreateArgs<PaymentsViewModel>(x => x.FiltroDataFim));
            }
        }

        private void FilterInvoicesByDate()
        {
            if (SAFT.SaftAnalyser.Instance.SaftFile != null && SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.SalesInvoices != null)
            {
                var inv = from i in SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.Payments.Payment
                          where i.TransactionDate >= filtroDataInicio && i.TransactionDate <= FiltroDataFim
                          select i;

                this.Payment = inv.ToArray();
            }
        }

        string filterPayment;
        public string FilterPayment
        {
            get { return filterPayment; }
            set
            {
                filterPayment = value;

                if (string.IsNullOrEmpty(filterPayment))
                    this.Payment = SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.Payments.Payment;
                else
                {
                    var inv = from i in SAFT.SaftAnalyser.Instance.SaftFile.SourceDocuments.Payments.Payment
                              where i.PaymentRefNo.IndexOf(filterPayment, StringComparison.OrdinalIgnoreCase) >= 0 ||
                              i.CustomerID.IndexOf(filterPayment, StringComparison.OrdinalIgnoreCase) >= 0
                              select i;

                    this.Payment = inv.ToArray();
                }
            }
        }

        string filterLines;
        public string FilterLines
        {
            get { return filterLines; }
            set
            {
                filterLines = value;

                if (string.IsNullOrEmpty(filterLines))
                    this.CurrentPaymentLines = this.CurrentPayment.Line;
                else
                {
                    var lines = from l in this.CurrentPayment.Line
                                where l.LineNumber.IndexOf(filterLines, StringComparison.OrdinalIgnoreCase) >= 0 ||
                                        l.SourceDocumentID.Any(s=> s.OriginatingON.IndexOf(filterLines, StringComparison.OrdinalIgnoreCase) >= 0)
                                select l;

                    this.CurrentPaymentLines = lines.ToArray();
                }
            }
        }

        public string DocGrossTotal { get; set; }

        public string DocNetTotal { get; set; }

        public string DocTaxPayable { get; set; }

        public int DocNumberOfEntries { get; set; }

        public string DocTotalCredit { get; set; }

        public string DocTotalDebit { get; set; }


        public string GrossTotal { get; set; }

        public string NetTotal { get; set; }

        public string TaxPayable { get; set; }

        public string NumberOfEntries { get; set; }

        public string TotalCredit { get; set; }

        public string TotalDebit { get; set; }
        #endregion

        #region Commands
        
        public SimpleCommand<object, object> DoOpenExcelCommand { get; private set; }
        private void OpenExcel(object args)
        {
            PaymentViewModel.OpenPaymentInExcel(this.CurrentPayment, this.ShowAllLines ? this.Payments.Payment.SelectMany(p=> p.Line).ToArray() : this.CurrentPaymentLines);
        }
        private bool CanOpenExcel(object args)
        {
            return CurrentPayment != null;
        }

        public SimpleCommand<object, object> ShowInvoiceDetailsCommand { get; private set; }
        private void DoShowInvoiceDetails(object args)
        {
            //Workspace.Workspace.Instance.ShowInvoiceDetails(this.CurrentPayment);
        }
        private bool CanShowInvoiceDetails(object args)
        {
            return this.CurrentPayment != null;
        }

        public SimpleCommand<object, object> ShowCustomerCommand { get; private set; }
        private void DoShowCustomer(object args)
        {
            //Workspace.Workspace.Instance.ShowCustomer(this.CurrentPayment.Pk);
        }
        private bool CanShowCustomer(object args)
        {
            return this.CurrentPayment != null;
        }
        #endregion

        private int Operation(SourceDocumentsPaymentsPaymentLine l)
        {
            return l.ItemElementName == ItemChoiceType9.CreditAmount ? 1 : -1;
        }
    }
}
